package org.easy.core.util;


import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;


public class Lists {
    @SafeVarargs
    public static <T> ArrayList<T> newArrayList(T... elements) {
        if (elements == null) {
            return null;
        } else {
            ArrayList<T> list = newArrayList();
            Collections.addAll(list, elements);
            return list;
        }
    }

    @SafeVarargs
    public static <T> List<T> list(T... elements) {
        if (elements == null) {
            return null;
        } else {
            ArrayList<T> list = newArrayList();
            Collections.addAll(list, elements);
            return list;
        }
    }

    public static <T> ArrayList<T> newArrayList(Iterable<? extends T> elements) {
        return elements == null ? null : (ArrayList) Streams.stream(elements).collect(Collectors.toCollection(ArrayList::new));
    }

    public static <T> ArrayList<T> newArrayList(Iterator<? extends T> elements) {
        return elements == null ? null : (ArrayList) Streams.stream(elements).collect(Collectors.toCollection(ArrayList::new));
    }

    public static <T> ArrayList<T> newArrayList() {
        return new ArrayList();
    }

    public static <T> List<T> emptyList() {
        return Collections.emptyList();
    }

    private Lists() {
    }

    public static <T> List<T> list(boolean isLinked) {
        return (List) (isLinked ? new LinkedList() : new ArrayList());
    }

    @SafeVarargs
    public static <T> List<T> list(boolean isLinked, T... values) {
        if (ObjectUtil.isEmpty(values)) {
            return list(isLinked);
        } else {
            List<T> arrayList = isLinked ? new LinkedList() : new ArrayList(values.length);
            Collections.addAll((Collection) arrayList, values);
            return (List) arrayList;
        }
    }

    public static <T> List<T> list(boolean isLinked, Collection<T> collection) {
        if (null == collection) {
            return list(isLinked);
        } else {
            return (List) (isLinked ? new LinkedList(collection) : new ArrayList(collection));
        }
    }

    public static <T> List<T> list(boolean isLinked, Iterable<T> iterable) {
        return null == iterable ? list(isLinked) : list(isLinked, iterable.iterator());
    }

    public static <T> List<T> list(boolean isLinked, Iterator<T> iter) {
        List<T> list = list(isLinked);
        if (null != iter) {
            while (iter.hasNext()) {
                list.add(iter.next());
            }
        }

        return list;
    }

    public static <T> List<T> list(boolean isLinked, Enumeration<T> enumration) {
        List<T> list = list(isLinked);
        if (null != enumration) {
            while (enumration.hasMoreElements()) {
                list.add(enumration.nextElement());
            }
        }

        return list;
    }

    @SafeVarargs
    public static <T> ArrayList<T> toList(T... values) {
        return (ArrayList) list(false, values);
    }

    @SafeVarargs
    public static <T> LinkedList<T> toLinkedList(T... values) {
        return (LinkedList) list(true, values);
    }

    @SafeVarargs
    public static <T> List<T> of(T... ts) {
        return ObjectUtil.isEmpty(ts) ? Collections.emptyList() : Collections.unmodifiableList(toList(ts));
    }

    public static <T> CopyOnWriteArrayList<T> toCopyOnWriteArrayList(Collection<T> collection) {
        return null == collection ? new CopyOnWriteArrayList() : new CopyOnWriteArrayList(collection);
    }

    public static <T> ArrayList<T> toList(Collection<T> collection) {
        return (ArrayList) list(false, collection);
    }

    public static <T> ArrayList<T> toList(Iterable<T> iterable) {
        return (ArrayList) list(false, iterable);
    }

    public static <T> ArrayList<T> toList(Iterator<T> iterator) {
        return (ArrayList) list(false, iterator);
    }

    public static <T> ArrayList<T> toList(Enumeration<T> enumeration) {
        return (ArrayList) list(false, enumeration);
    }


    public static <T> List<T> sub(List<T> list, int start, int end) {
        return sub(list, start, end, 1);
    }

    public static <T> List<T> sub(List<T> list, int start, int end, int step) {
        if (list == null) {
            return null;
        } else if (list.isEmpty()) {
            return new ArrayList(0);
        } else {
            int size = list.size();
            if (start < 0) {
                start += size;
            }

            if (end < 0) {
                end += size;
            }

            if (start == size) {
                return new ArrayList(0);
            } else {
                if (start > end) {
                    int tmp = start;
                    start = end;
                    end = tmp;
                }

                if (end > size) {
                    if (start >= size) {
                        return new ArrayList(0);
                    }

                    end = size;
                }

                if (step < 1) {
                    step = 1;
                }

                List<T> result = new ArrayList();

                for (int i = start; i < end; i += step) {
                    result.add(list.get(i));
                }

                return result;
            }
        }
    }


    public static <T> List<T> unmodifiable(List<T> list) {
        return null == list ? null : Collections.unmodifiableList(list);
    }

    public static <T> List<T> empty() {
        return Collections.emptyList();
    }


}
